﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Core
{
    /// <summary>
    /// 枚举类基类
    /// </summary>
    /// <typeparam name="TKey">Id键类型</typeparam>
    public abstract class Enumeration<TKey> : IComparable
    {
        /// <summary>
        /// 枚举类名称
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// 枚举类Id
        /// </summary>
        public TKey Id { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        protected Enumeration(TKey id, string name) => (Id, Name) = (id, name);

        public override string ToString() => Name;

        /// <summary>
        /// 获取全部枚举类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<T> GetAll<T>() where T : Enumeration<TKey> =>
            typeof(T).GetFields(BindingFlags.Public |
                                BindingFlags.Static |
                                BindingFlags.DeclaredOnly)
                     .Select(f => f.GetValue(null))
                     .Cast<T>();

        public override bool Equals(object obj)
        {
            if (obj is not Enumeration<TKey> otherValue)
            {
                return false;
            }

            var typeMatches = GetType().Equals(obj.GetType());
            var valueMatches = Id.Equals(otherValue.Id);

            return typeMatches && valueMatches;
        }

        public int CompareTo(object other) => Id.GetHashCode().CompareTo(((Enumeration<TKey>)other).Id.GetHashCode());

        public static T FromNamed<T>(string typeNamed)
            where T : Enumeration<TKey>
        {
            return GetAll<T>().Where(t => String.Equals(t.Name, typeNamed, StringComparison.OrdinalIgnoreCase))
                .FirstOrDefault();
        }

        public static bool TryFromNamed<T>(string typeNamed, out T result)
            where T : Enumeration<TKey>
        {
            try
            {
                result = FromNamed<T>(typeNamed);
                return result != null;
            }
            catch (Exception)
            {
                result = default(T);
                return false;
            }
        }

        public static T FormValue<T>(TKey value)
            where T : Enumeration<TKey>
        {
            return GetAll<T>().Where(t => t.Id.Equals(value))
                   .FirstOrDefault();
        }

        public static bool TryFormValue<T>(TKey value, out T result)
            where T : Enumeration<TKey>
        {
            try
            {
                result = FormValue<T>(value);
                return result != null;
            }
            catch (Exception)
            {
                result = default(T);
                return false;
            }
        }
    }
}
